package network;

import android.app.Application;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import java.util.HashMap;
import java.util.List;

import jsonParser.ParserFactory;

public class NetConnectTask extends AsyncTask<Void, Void, Boolean> implements NetConnectClient.AppendInfo {

    private static final String TAG = "NetConnectTask";

    // 基本请求参数
    public static final String MIEI_CODE_TAG = "imei";
    public static final String MODEL_NUMBER_TAG = "model";
    public static final String ELAPSED_TIME_TAG = "elapsedtime";
    public static final String APP_VERSION_CODE = "app_ver"; // app版本

    public Context mContext;

    private NetConnectClient mConnect;

    /**
     * try to connect times
     */
    private int mTryNum;

    /**
     * request url
     */
    private String mUrl;

    /**
     * request params
     */
    private HashMap<String, String> mParams;

    private List<String> mKeyValues;

    /**
     * connect type: get or post
     */
    private int mConnectType;

    /**
     * custom net status code
     */
    private int mConnectStatus;

    /**
     * http status code
     */
    private int mHttpCode;

    /**
     * data was returned by net
     */
    private String mData;

    /**
     * object was parser by {@link ParserFactory}
     */
    private Object mParsedObj = null;

    /**
     * when use this task, must implement the interface for response data
     */
    private NetResponseListener mListener;

    private NetDataParseListener mParseListener;

    private ParserFactory mParser;

    private boolean mIsFinish = false;

    /**
     * net connect timeout
     */
    private int mTimeOut = 0;

    /**
     * @param context
     * @param url:    request url
     */
    public NetConnectTask(Context context, String url) {
        this(context, url, new HashMap<String, String>(), NetConnectClient.CONNECT_TYPE_HTTPCLIENT_GET);
    }

    /**
     * @param context
     * @param url:         request url
     * @param params:      request params
     * @param connectType: request type
     */
    public NetConnectTask(Context context, String url, HashMap<String, String> params, int connectType) {

        // 获取application的context
        if (!(context instanceof Application)) {
            mContext = context.getApplicationContext();
        } else {
            mContext = context;
        }
        mUrl = url;
        mParams = params;
        mConnectType = connectType;
    }

    /**
     * @param context
     * @param listener: the result of parser
     * @param parser:
     * @param url:      request url
     * @param params:   request params
     */
    public NetConnectTask(Context context, NetDataParseListener listener, ParserFactory parser, String url,
                          HashMap<String, String> params) {

        if (listener == null) {
            throw new IllegalArgumentException("NetDataParseListener can't be null");
        }

        if (parser == null) {
            throw new IllegalArgumentException("mParser can't be null");
        }

        mParser = parser;
        mParseListener = listener;

        // 获取application的context
        if (!(context instanceof Application)) {
            mContext = context.getApplicationContext();
            Log.d(TAG, "not Application context");
        } else {
            mContext = context;
            Log.d(TAG, "Application context");
        }
        mUrl = url;
        mParams = params;
        mConnectType = NetConnectClient.CONNECT_TYPE_HTTPCLIENT_GET;
    }

    public void setNetResponseListener(NetResponseListener listener) {

        mListener = listener;
    }

    public void setKeyValues(List<String> keyValues) {

        this.mKeyValues = keyValues;
    }

    public void setNetDataParseListener(NetDataParseListener listener) {

        mParseListener = listener;
    }

    /**
     * set connect type: get or post
     *
     * @param type
     */
    public void setConnectType(int type) {

        mConnectType = type;
    }

    /**
     * set ParserFactory
     *
     * @param parser
     */
    public void setJsonParser(ParserFactory parser) {

        mParser = parser;
    }

    /**
     * set try to connect times of net, default times is  NetConnectClient.DEFAULT_TRY_NUM
     *
     * @param times
     */
    public void setConnectTimes(int times) {

        mTryNum = times;
    }

    /**
     * set net connect timeout, default time is  NetConnectClient.SOCKET_OPERATION_TIMEOUT
     *
     * @param timeout
     */
    public void setTimeout(int timeout) {

        mTimeOut = timeout;
    }

    @Override
    public void onCancelled() {

        if (mConnect != null) {
            mConnect.disconnect();
        }
    }

    @Override
    protected void onPostExecute(Boolean result) {

        if (mListener != null) {
            mListener.onResponse(isCancelled(), mData, mConnectStatus);
        }

        if (mParseListener != null) {
            mParseListener.onParse(isCancelled(), mData, mConnectStatus, mParsedObj);
        }

        mIsFinish = true;
    }

    @Override
    protected Boolean doInBackground(Void... params) {

        boolean isCancel = false;
        if (isCancelled()) {
            return true;
        }

        if (mTimeOut > 0) {
            mConnect = new NetConnectClient(mContext, new Response(), mTimeOut);
        } else {
            mConnect = new NetConnectClient(mContext, new Response());
        }

        if (mTryNum > 0) {
            mConnect.setTryNum(mTryNum);
        }

        mConnect.setAppendInfo(this);
        if (mKeyValues != null) {
            mConnect.setMultiKeyValues(mKeyValues);
        }
        mConnect.connect(mUrl, mParams, mConnectType);

        if (isCancelled()) {
            return true;
        }

        return isCancel;
    }

    public interface NetResponseListener {

        /**
         * interface for task execute finished
         *
         * @param isCancel:   whether task is cancel by interrupt or not
         * @param data:       data from net
         * @param connStatus: custom status code in {@link NetConnectResponse}
         */
        public void onResponse(boolean isCancel, String data, int connStatus);
    }

    public interface NetDataParseListener {

        /**
         * interface for task execute finished
         *
         * @param isCancel:   whether task is cancel by interrupt or not
         * @param data:       data from net
         * @param connStatus: custom status code in {@link NetConnectResponse}
         * @param obj:        parser data from {@link ParserFactory}
         */
        public void onParse(boolean isCancel, String data, int connStatus, Object obj);
    }

    private class Response implements NetConnectResponse {

        @Override
        public void response(NetConnectClient connect, int connStatus, int httpCode, String data) {

            connect.disconnect();
            mData = data;
            mConnectStatus = connStatus;
            mHttpCode = httpCode;
            Log.d(TAG, "data " + data + " connStatus " + connStatus + " httpCode " + httpCode);

            if (mParser != null && connStatus == NetConnectResponse.CONNECT_SUCCESS && !TextUtils.isEmpty(data)) {
                mParsedObj = mParser.parseData(data);
            }
        }

    }

    /**
     * don't execute task, directly get data by HttpConnect in thread
     */
    public void connect() {

        if (mTimeOut > 0) {
            mConnect = new NetConnectClient(mContext, new Response(), mTimeOut);
        } else {
            mConnect = new NetConnectClient(mContext, new Response());
        }

        if (mTryNum > 0) {
            mConnect.setTryNum(mTryNum);
        }

        mConnect.setAppendInfo(this);
        mConnect.connect(mUrl, mParams, mConnectType);

        if (mListener != null) {
            mListener.onResponse(false, mData, mConnectStatus);
        }

        if (mParseListener != null) {
            mParseListener.onParse(false, mData, mConnectStatus, mParsedObj);
        }

        mIsFinish = true;
    }

    /**
     * check this task has finish
     *
     * @return
     */
    public boolean isTaskFinish() {

        return mIsFinish;
    }

    public int getConnectStatus() {

        return mConnectStatus;
    }

    public int getHttpCode() {

        return mHttpCode;
    }

    public String getData() {

        return mData;
    }

    public Object getParsedObj() {

        return mParsedObj;
    }

    private String appendGreneralInfomation(String url) {

        HashMap<String, String> params = new HashMap<String, String>();

//        final String mieiCode = SystemUtils.getImei(mContext);
        final String mieiCode = "get miei";
        final String modelNumber = Build.MODEL;
        final long elapsedTime = SystemClock.elapsedRealtime();

        if (mieiCode == null || mieiCode.equals("0")) {
            params.put(MIEI_CODE_TAG, "012345678987654");
        } else {
            params.put(MIEI_CODE_TAG, mieiCode);
        }

        params.put(MODEL_NUMBER_TAG, modelNumber);
        params.put(ELAPSED_TIME_TAG, String.valueOf(elapsedTime));

        params.put(APP_VERSION_CODE, "v1.0"); //  app版本

        // 添加各种参数
//        params.put(RequestParams.U_ID_TAG, SystemUtils.getUfsid());
//        params.put(RequestParams.ANDROID_VER, String.valueOf(Build.VERSION.SDK_INT));
//        params.put(RequestParams.ANDROID_NAME, String.valueOf(Build.VERSION.RELEASE));
//
//        if (Build.VERSION.SDK_INT > VersionCodes.JELLY_BEAN_MR1) {
//            params.put(RequestParams.PIC_TYPE, RequestParams.PARAM_PIC_WEBP);
//        }
//
//        params.put(RequestParams.SCREEN_DENSITY, String.valueOf(utils.getScreenDensity()));
//        params.put(RequestParams.SCREEN_SIZE, String.valueOf(utils.getScreenWidth()) + "_" + utils.getScreenHeight());
//        String nt = NetUtils.getConnectionTypeName(utils.getApplication());
//        params.put(RequestParams.PARAM_NETWORK_TYPE, nt == null ? "null" : nt);
//        params.put(RequestParams.LOCATION_LONGITUDE, String.valueOf(LocationUtils.getLongitude()));
//        params.put(RequestParams.LOCATION_LATITUDE, String.valueOf(LocationUtils.getLatitude()));
//        params.put(RequestParams.SIGNATURE, String.valueOf(CommonHelpers.isSystemSignature(mContext)));
//        params.put(RequestParams.GIT_ID, CommonHelpers.getGitId(mContext));

        return NetUtils.organizeUrlParam(url, params);
    }

    @Override
    public String onAppendRequestInfo(String url) {

        return appendGreneralInfomation(url);
    }
}
